/*************************************************************************
 *                                                                       *
 * This file is part of the FreeMAPs distribution.  For full copyright   *
 * information, see COPYRIGHT and COPYING.LESSER.                        *
 *                                                                       *
 * Author:           sqbang                                              *
 * Email:            sqbang@ustc.edu                                     *
 * Date:             2013.11.19                                          *
 *                                                                       *
 *************************************************************************/

#ifndef FreeMAPs_include_COMMON_mesh_MeshGroup_h
#define FreeMAPs_include_COMMON_mesh_MeshGroup_h

#include "FreeMAPsConfig.h"

//FreeMAPs headers
//#include "COMMON/enum/ElemType.h"
#include "COMMON/mesh/NodeGroup.h"
//#include "COMMON/mesh/ElemGroup.h"
//#include "COMMON/mesh/SideGroup.h"
//#include "COMMON/mesh/EdgeGroup.h"
//#include "COMMON/mesh/Elem.h"
#include "COMMON/tbox/Bimap.h"

namespace FreeMAPs
{

/**
 * @brief MeshGroup used to save all groups used in unstructured mesh.
 *
 * The groups include those groups used to build sub-region, boundary...
 * Groups is identitied by it's name.
 *
 * @note that use it to build unstructured mesh.
 * after the mesh is build, do NOT use it any more to save memory.
 */
class MeshGroup
{
public:

    MeshGroup();
    ~MeshGroup();

public:

    inline void
    insert_node_group (
        const NodeGroup& node_group);

    inline void
    insert_node_to_node_group (
        const std::string& group_name,
        const int node_id);
#if 0
    inline void
    insert_side_group (
        const SideGroup& side_group);

    inline void
    insert_edge_group (
        const EdgeGroup& edge_group);

    inline void
    insert_elem_group (
        const ElemGroup& elem_group);

    inline void
    insert_elem_to_elem_group (
        const std::string& subdomain_name,
        const int elem_id);
#endif
    inline const std::map<std::string, NodeGroup>&
    get_node_groups() const;
#if 0
    inline const std::map<std::string, SideGroup>&
    get_side_groups() const;

    inline const std::map<std::string, EdgeGroup>&
    get_edge_groups() const;

    inline const std::map<std::string, ElemGroup>&
    get_elem_groups() const;

    inline int
    get_subdomain_id (
        const std::string& subdomain_name) const;

    inline const Bimap<std::string, int>&
    get_subdomain_names() const;

    inline bool
    has_node_group(
        const std::string& group_name) const;

    inline bool
    has_side_group(
        const std::string& group_name) const;

    inline bool
    has_edge_group(
        const std::string& group_name) const;

    inline bool
    has_elem_group(
        const std::string& group_name) const;

    inline int
    get_boundary_id (
        const std::string& bd_name) const;
#endif
public:

    void
    clear();
#if 0
    void
    remove_empty_group();

    /**
     * renumber all nodes using it's new id.
     * the node_id_map<old_node_id, new_node_id>
     */
    void
    renumber_nodes (
        const std::map<int, int>& node_id_map);

    /**
     * set the elem's subdomain id by elem_group
     */
    void
    set_elem_subdomain_id (
        std::vector<Elem>& elems) const;

    /**
     * set subdomain_name by elems.
     */
    void
    set_subdomain_names(
        const std::vector<Elem>& elems);

    friend std::ostream&
    operator << (
        std::ostream& os,
        const MeshGroup& rhs);
#endif
private:

    /*
     * map<group name, group>
     * these two group is used mainly as boundary.
     */
    std::map<std::string, NodeGroup> d_node_groups;
//    std::map<std::string, SideGroup> d_side_groups;
//    std::map<std::string, EdgeGroup> d_edge_groups;

    Bimap<std::string, int> d_boundary_names;

    /*
     * elem group will be taken as sub-domain.
     * evaluate each subdomain a id.
     * Bimap<elem_group_name, subssdomain_id>
     */
//    std::map<std::string, ElemGroup> d_elem_groups;
//    Bimap<std::string, int> d_subdomain_names;
};

}

#include "COMMON/mesh/MeshGroup.inl"

#endif
